package cool.taomu.toolkit.watcher

import com.google.common.eventbus.EventBus
import com.google.inject.Inject
import com.google.inject.name.Named
import cool.taomu.toolkit.watcher.entity.FileCreateEvent
import cool.taomu.toolkit.watcher.entity.FileDeleteEvent
import cool.taomu.toolkit.watcher.entity.FileModifyEvent
import java.io.IOException
import java.nio.file.FileVisitResult
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths
import java.nio.file.SimpleFileVisitor
import java.nio.file.StandardWatchEventKinds
import java.nio.file.WatchEvent
import java.nio.file.WatchKey
import java.nio.file.WatchService
import java.nio.file.attribute.BasicFileAttributes
import java.util.HashMap
import java.util.Map
import org.slf4j.LoggerFactory

class DirectoryWatcher {
	val static LOG = LoggerFactory.getLogger(DirectoryWatcher)

	val WatchService watchService;

	val EventBus eventBus;

	@Inject
	@Named("taomu.fileWatch")
	String rootDirStr;

	static final Map<WatchEvent.Kind<?>, Class<?>> EVENT_MAP = new HashMap();

	@Inject
	new(WatchService watchService, EventBus eventBus) {
		EVENT_MAP.put(StandardWatchEventKinds.ENTRY_CREATE, FileCreateEvent);
		EVENT_MAP.put(StandardWatchEventKinds.ENTRY_MODIFY, FileModifyEvent);
		EVENT_MAP.put(StandardWatchEventKinds.ENTRY_DELETE, FileDeleteEvent);
		this.watchService = watchService;
		this.eventBus = eventBus;
	}

	def void watch() throws IOException,InterruptedException {
		var Path rootDir = Paths.get(rootDirStr);
		LOG.info("监控路径:{}", rootDir.toFile.absolutePath)
		registerRecursive(rootDir);

		while (true) {
			val WatchKey key = watchService.take()
			var events = key.pollEvents()
			events.forEach [ event |
				if (event.kind !== StandardWatchEventKinds.OVERFLOW) {
					var ev = event as WatchEvent<Path>
					var fullPath = (key.watchable as Path).resolve(ev.context)
					var eventType = EVENT_MAP.get(event.kind());
					try {
						var Object eventInstance = eventType.getConstructor(
							Path
						).newInstance(fullPath);
						eventBus.post(eventInstance);
						println(eventType.name)
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			]
			key.reset();
		}
	}

	def void registerRecursive(Path dir) throws IOException
    {
		Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {
			override FileVisitResult preVisitDirectory(Path subDir, BasicFileAttributes attrs) throws IOException {
				subDir.register(watchService, StandardWatchEventKinds.ENTRY_CREATE,
					StandardWatchEventKinds.ENTRY_DELETE, StandardWatchEventKinds.ENTRY_MODIFY);
				return FileVisitResult.CONTINUE;
			}
		});
	}
}
